package com;

import javax.swing.*;

import com.trusfort.redis.RedisServiceUtil;
import com.util.FileUtils;

import redis.clients.jedis.resps.ScanResult;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;

public class RedisKeyDelete {
    // UI组件
    private static JTextField txtRedisAddress;
    private static JPasswordField txtRedisPassword;
    private static JTextField txtSavePath;
    private static JTextArea txtLog;
    private static JTextArea txtResult;
    private static JComboBox<Integer> dbComboBox;
    private static JTextField txtKeyPrefix;
    private static JComboBox<String> deploymentComboBox; // 新增：部署方式下拉框
    private static JFrame jf;

    // 配置常量
    private static final String[] excludes = {"mtd", "XDID", "qlog"};
    private static final int SCAN_BATCH_SIZE = 1000;
    private static final int THREAD_POOL_SIZE = 4;

    // 运行时状态
    private final Map<String, Map<String, Long>> data = new ConcurrentHashMap<>();
    private final AtomicLong totalKeys = new AtomicLong(0);
    private static volatile boolean isRunning = false;
    private static CommandLineParams params ;

    public static void main(String[] args) {
        // 命令行模式判断
        if (args.length > 0 && ("--cli".equals(args[0]) || "-c".equals(args[0]))) {
            runInCommandLineMode(args);
        } else {
            runInUIMode();
        }
    }

    /**
     * 命令行模式运行
     */
    private static void runInCommandLineMode(String[] args) {
        try {
            params = parseCommandLineArgs(args);
            RedisKeyDelete deleter = new RedisKeyDelete();
            deleter.executeTask(params.redisAddress, params.redisPassword, 
                              params.dbIndex, params.keyPrefix, params.logPath,params.deploymentMode);
        } catch (Exception e) {
            System.err.println("执行出错: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 解析命令行参数
     */
    private static CommandLineParams parseCommandLineArgs(String[] args) {
        CommandLineParams params = new CommandLineParams();
        for (int i = 1; i < args.length; i++) {
            switch (args[i]) {
                case "-h":
                    params.redisAddress = args[++i];
                    break;
                case "-p":
                    params.redisPassword = args[++i];
                    break;
                case "-d":
                    params.dbIndex = Integer.parseInt(args[++i]);
                    break;
                case "-k":
                    params.keyPrefix = args[++i];
                    break;
                case "-o":
                    params.logPath = args[++i];
                    break;
                case "-m":
                    params.deploymentMode = args[++i];
                    break;
            }
        }
        return params;
    }

    /**
     * UI模式运行
     */
    private static void runInUIMode() {
        jf = new JFrame("Redis数据清理工具 v1.0");
        jf.setSize(1000, 750);
        jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        jf.setLocationRelativeTo(null);

        JPanel mainPanel = new JPanel(new BorderLayout(5, 5));
        mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        // 顶部控制面板
        JPanel controlPanel = createControlPanel();
        mainPanel.add(controlPanel, BorderLayout.NORTH);

        // 中间日志面板
        JPanel logPanel = createLogPanel();
        mainPanel.add(logPanel, BorderLayout.CENTER);

        // 底部结果面板
        JPanel resultPanel = createResultPanel();
        mainPanel.add(resultPanel, BorderLayout.SOUTH);

        jf.setContentPane(mainPanel);
        jf.setVisible(true);
    }

    /**
     * 创建控制面板
     */
    private static JPanel createControlPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBorder(BorderFactory.createTitledBorder("控制面板"));
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 5, 5, 5);
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // 第一行
        gbc.gridy = 0;
        gbc.gridx = 0;
        panel.add(new JLabel("Redis地址:"), gbc);

        gbc.gridx = 1;
        gbc.weightx = 1;
        txtRedisAddress = new JTextField("localhost:6379");
        panel.add(txtRedisAddress, gbc);

        gbc.gridx = 2;
        gbc.weightx = 0;
        
        panel.add(new JLabel("部署方式:"), gbc);

        gbc.gridx = 3;
        gbc.weightx = 1;
        String[] deploymentOptions = {"single", "cluster"};
        deploymentComboBox = new JComboBox<>(deploymentOptions);
        panel.add(deploymentComboBox, gbc);
        
        // 添加部署方式切换事件
        deploymentComboBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String selectedMode = (String) deploymentComboBox.getSelectedItem();
                if ("cluster".equals(selectedMode)) {
                    // 集群模式下禁用DB索引选择
                    dbComboBox.setEnabled(false);
                    dbComboBox.setSelectedIndex(0); // 集群模式默认使用0号数据库
                    logInfo("切换到集群模式，DB索引已禁用（使用默认数据库0）");
                } else {
                    // 单机模式下启用DB索引选择
                    dbComboBox.setEnabled(true);
                    logInfo("切换到单机模式，DB索引已启用");
                }
            }
        });

        // 第二行
        gbc.gridy = 1;
        gbc.gridx = 0;
        panel.add(new JLabel("日志路径:"), gbc);

        gbc.gridx = 1;
        txtSavePath = new JTextField(System.getProperty("user.home") + "/redis_clean_logs");
        panel.add(txtSavePath, gbc);

        gbc.gridx = 2;
        
        panel.add(new JLabel("密码:"), gbc);

        gbc.gridx = 3;
        txtRedisPassword = new JPasswordField();
        panel.add(txtRedisPassword, gbc);
        
        // 第三行
        gbc.gridy = 2;
        gbc.gridx = 0;
        panel.add(new JLabel("Key前缀:"), gbc);

        gbc.gridx = 1;
        txtKeyPrefix = new JTextField();
        panel.add(txtKeyPrefix, gbc);

        gbc.gridx = 2;
        gbc.gridwidth = 2;
        
        // 新增：部署方式下拉框
        gbc.gridx = 2;
        panel.add(new JLabel("DB索引:"), gbc);

        gbc.gridx = 3;
        Integer[] dbOptions = new Integer[17];
        for (int i = 0; i <= 16; i++) dbOptions[i] = i;
        dbComboBox = new JComboBox<>(dbOptions);
        panel.add(dbComboBox, gbc);
        
       
        
        // 第四行：按钮行（居中显示）
        gbc.gridy = 3;
        gbc.gridx = 0;
        gbc.gridwidth = 4; // 跨4列
        gbc.anchor = GridBagConstraints.CENTER; // 居中
        
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 0));
        buttonPanel.add(createButton("开始删除", e -> startTask()));
        buttonPanel.add(createButton("停止", e -> stopTask()));
        buttonPanel.add(createButton("清空日志", e -> clearLog()));
        
        panel.add(buttonPanel, gbc);

        return panel;
    }

    /**
     * 创建日志面板
     */
    private static JPanel createLogPanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createTitledBorder("操作日志"));
        panel.setPreferredSize(new Dimension(0, 300));

        txtLog = new JTextArea();
        txtLog.setEditable(false);
        txtLog.setFont(new Font("Monospaced", Font.PLAIN, 12));
        JScrollPane scrollPane = new JScrollPane(txtLog);
        panel.add(scrollPane, BorderLayout.CENTER);

        return panel;
    }

    /**
     * 创建结果面板
     */
    private static JPanel createResultPanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createTitledBorder("执行结果"));
        panel.setPreferredSize(new Dimension(0, 200));

        txtResult = new JTextArea();
        txtResult.setEditable(false);
        txtResult.setFont(new Font("Monospaced", Font.PLAIN, 12));
        JScrollPane scrollPane = new JScrollPane(txtResult);
        panel.add(scrollPane, BorderLayout.CENTER);

        return panel;
    }

    /**
     * 创建按钮
     */
    private static JButton createButton(String text, ActionListener listener) {
        JButton button = new JButton(text);
        button.setPreferredSize(new Dimension(100, 30));
        button.addActionListener(listener);
        return button;
    }

    /**
     * 开始任务
     */
    private static void startTask() {
        if (isRunning) {
            logInfo("已有任务在运行，请等待完成");
            return;
        }

        new Thread(() -> {
            RedisKeyDelete deleter = new RedisKeyDelete();
            deleter.executeTask(
                txtRedisAddress.getText(),
                new String(txtRedisPassword.getPassword()),
                (Integer) dbComboBox.getSelectedItem(),
                txtKeyPrefix.getText(),
                txtSavePath.getText(),
                (String) deploymentComboBox.getSelectedItem()
            );
        }).start();
    }

    /**
     * 停止任务
     */
    private static void stopTask() {
        isRunning = false;
        logInfo("用户手动停止扫描");
    }

    /**
     * 清空日志
     */
    private static void clearLog() {
        SwingUtilities.invokeLater(() -> txtLog.setText(""));
        logInfo("日志已清空");
    }

    /**
     * 执行清理任务
     */
    public void executeTask(String redisAddress, String redisPassword, 
                          int dbIndex, String keyPrefix, String logPath,String deploymentMode) {
        isRunning = true;
        totalKeys.set(0);
        data.clear();

        try {
            validateParams(redisAddress, logPath);

            logInfo("Redis Key清理任务开始 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            logInfo(String.format("连接Redis: %s, DB: %d", redisAddress, dbIndex));

            RedisServiceUtil.init(deploymentMode, redisAddress, 
                    redisPassword.isEmpty() ? null : redisPassword);

           
            deleteKeys(dbIndex, keyPrefix);

            logInfo("所有清理完成，总计删除key数量: " + totalKeys.get());
            showResult(formatResults(data));
        } catch (Exception e) {
            logError("任务执行出错", e);
        } finally {
            isRunning = false;
        }
    }

    /**
     * 参数验证
     */
    private void validateParams(String redisAddress, String logPath) {
//        String[] parts = redisAddress.split(":");
//        if (parts.length != 2) {
//            throw new IllegalArgumentException("Redis地址格式不正确，请使用IP:PORT格式");
//        }
//        try {
//            Integer.parseInt(parts[1]);
//        } catch (NumberFormatException e) {
//            throw new IllegalArgumentException("Redis端口号必须是数字");
//        }
    }

    /**
     * 删除keys
     */
    private void deleteKeys(int dbIndex, String pattern) {
        ExecutorService executor = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
        try {
            String cursor = "0";
            int batchCount = 0;
            long startTime = System.currentTimeMillis();

            do {
                ScanResult<String> result = RedisServiceUtil.scan(dbIndex, pattern+"*", cursor, SCAN_BATCH_SIZE);
                List<String> keys = result.getResult();

                if (keys != null && !keys.isEmpty()) {
                    batchCount++;
                    executor.submit(() -> processKeys(dbIndex, pattern, keys));

                    if (batchCount % 10 == 0) {
                        logInfo(String.format("处理进度: 已扫描 %d 个key", totalKeys.get()));
                    }
                }
                cursor = result.getCursor();
            } while (!cursor.equals("0") && isRunning);

            executor.shutdown();
            executor.awaitTermination(1, TimeUnit.HOURS);

            logInfo(String.format("扫描完成 %s: 总计 %d 个key, 耗时 %.2f秒", 
                   pattern, totalKeys.get(), (System.currentTimeMillis() - startTime) / 1000.0));
        } catch (Exception e) {
            throw new RuntimeException("扫描Keys出错", e);
        }
    }

    /**
     * 处理keys
     */
    private void processKeys(int dbIndex, String pattern, List<String> keys) {
        try {
            List<String> delList = new ArrayList<>();
            for (String key : keys) {
                if (!isExcluded(key) && key.startsWith(pattern)) {
                    delList.add(key);
                }
            }

            if (!delList.isEmpty()) {
            	totalKeys.addAndGet(delList.size());
                RedisServiceUtil.del(dbIndex, delList);
            }
        } catch (Exception e) {
            logError("处理Keys出错", e);
        }
    }

    /**
     * 检查key是否在排除列表中
     */
    private boolean isExcluded(String key) {
        for (String exclude : excludes) {
            if (key.startsWith(exclude)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 记录信息日志
     */
    public static void logInfo(String msg) {
        String timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        String logMsg = timestamp + " [INFO] " + msg;

        SwingUtilities.invokeLater(() -> {
        	if(txtLog!=null) {
        		txtLog.append(logMsg + "\n");
        	}
        	
        	if(txtSavePath != null) {
        		FileUtils.write(txtSavePath.getText() + "/redis_clean.log", logMsg);	
        	}else {
        		
        		FileUtils.write(params.logPath + "/redis_clean.log", logMsg);	
        	}
        		
        });

        System.out.println(logMsg);
    }

    /**
     * 记录错误日志
     */
    public static void logError(String msg, Exception e) {
        String timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        String logMsg = timestamp + " [ERROR] " + msg + ": " + e.getMessage();

        StringWriter sw = new StringWriter();
        e.printStackTrace(new PrintWriter(sw));
        String stackTrace = sw.toString();

        SwingUtilities.invokeLater(() -> {
            
            if(txtLog!=null) {
            	txtLog.append(logMsg + "\n" + stackTrace + "\n");
        	}
            
            if(txtSavePath != null) {
            	FileUtils.write(txtSavePath.getText() + "/redis_clean_error.log", logMsg + "\n" + stackTrace);
        	}else {
        		
        		FileUtils.write(params.logPath + "/redis_clean.log", logMsg);	
        	}
            
        });

        System.err.println(logMsg);
        e.printStackTrace();
    }

    /**
     * 显示结果
     */
    private static void showResult(String result) {
    	if(txtResult != null) {
    		SwingUtilities.invokeLater(() -> txtResult.setText(result));	
    	}else {
    		logInfo(result);
    	}
    }

    /**
     * 格式化结果
     */
    private String formatResults(Map<String, Map<String, Long>> data) {
        return String.format("清理完成，总计删除 %d 个key\n", totalKeys.get());
    }

    /**
     * 命令行参数类
     */
    private static class CommandLineParams {
        String redisAddress = "localhost:6379";
        String redisPassword = "";
        int dbIndex = 0;
        String keyPrefix = "";
        String logPath = System.getProperty("user.home") + "/redis_clean_logs";
        String deploymentMode = "single";
    }
}